package cz.cuni.amis.episodic.bayes.utils.chart;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.jfree.chart.ChartColor;
import org.jfree.chart.JFreeChart;
import org.jfree.data.Range;

import com.itextpdf.awt.PdfGraphics2D;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;

import cz.cuni.amis.episodic.bayes.utils.DynamicNodeProperty;
import cz.cuni.amis.episodic.bayes.utils.MemChart;
import cz.cuni.amis.episodic.dybanem.DBN;
import static cz.cuni.amis.episodic.bayes.utils.MemoryChartCreator.*;

/**
 * Class that draws all graphs for a single sequence as it is observed step by
 * step.
 * 
 * @author ik
 * 
 */
public class BeliefEvolutionChart {

	/**
	 * Places chart into PDF.
	 */
	static void placeChart(PdfContentByte cb, JFreeChart chart, int width,
			int height, int x, int y) {
		PdfTemplate template = cb.createTemplate(width, height);
		Graphics2D graphics = new PdfGraphics2D(template, width, height);
		Rectangle2D rect = new Rectangle2D.Double(0, 0, width, height);
		chart.draw(graphics, rect);
		graphics.dispose();
		cb.addTemplate(template, x, y);
	}

	/**
	 * Draws charts that show evolution of beliefs in one node over multiple
	 * time steps. Charts are: posterior probability, entropy and surprise.
	 * 
	 * @param nodeEvolutionList
	 *            list of beliefs in one node
	 * @param net
	 * @param graphDevice
	 * @throws IOException
	 * @throws Exception
	 */
	public static void createChartsForOneNode(
			List<DynamicNodeProperty> nodeEvolutionList, DBN net,
			PdfContentByte cb, double surpriseMax, double entropyMax) throws IOException, Exception {
		int width = 190;
		int height = 100;
		int timeColumnWidth = 30;

		// find max surprise and entropy
		double maxE = 0;
		double maxS = 0;
		for(DynamicNodeProperty nodeDynProp : nodeEvolutionList) {
			for(int i = 0; i < nodeDynProp.getEntropy().length; i++) {
				maxE = Math.max(maxE, nodeDynProp.getEntropy()[i]);
				maxS = Math.max(maxS, nodeDynProp.getSurprise()[i]);
			}
		}
		
		if(surpriseMax > 0) maxS = surpriseMax;
		if(entropyMax > 0) maxE = entropyMax;
		
		// draw the graphs
		for (int i = 0; i < nodeEvolutionList.size(); i++) {
			int index = nodeEvolutionList.size() - i - 1;

			DynamicNodeProperty nodeProp = nodeEvolutionList.get(i);

			JFreeChart posterior = addTimeMarker(i,
					MemChart.chartXYBlockTimeValue(nodeProp.getFullPosterior(),
							net.getNet().getOutcomeIds(nodeProp.getNode()),
							null));
			JFreeChart entropy = addTimeMarker(i, AreaChart.chart(
					nodeProp.getEntropy(), Color.green, new Range(0, maxE), null));
			JFreeChart surprise = addTimeMarker(i, AreaChart.chart(
					nodeProp.getSurprise(), ChartColor.DARK_YELLOW, new Range(0, maxS),
					null));

			placeChart(cb, posterior, width, height, timeColumnWidth, index * height);
			placeChart(cb, entropy, width, height, width + timeColumnWidth, index * height);
			placeChart(cb, surprise, width, height, 2 * width + timeColumnWidth, index * height);

			placeText(cb, 0, index * height + height/2, "t="+i);
		}
		
		// draw titles
		int titlesY = (nodeEvolutionList.size()) * height + 10; 
		int titleXoffset = timeColumnWidth + width/3;
		placeText(cb, titleXoffset, titlesY, "Belief");
		placeText(cb, titleXoffset + width, titlesY, "Uncertainty");
		placeText(cb, titleXoffset + 2*width, titlesY, "Surprise");
	}

	public static void placeText(PdfContentByte over, int x, int y, String text) {
	        over.saveState();
	        BaseFont bf = null;
			try {
				bf = BaseFont.createFont();
			} catch (DocumentException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
	        over.beginText();
	        over.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
	        //over.setLineWidth(1.5f);
	        over.setFontAndSize(bf, 18);
	        over.setTextMatrix(x, y);
	        over.showText(text);
	        over.endText();
	        over.restoreState();
	}
	
	/**
	 * Creates various graphs that can be extracted from the DynamicNodeProperty
	 * through the time.
	 * 
	 * @param nodeEvolutionList
	 */
	public static void createEvolutionCharts(
			List<DynamicNodeProperty[]> nodeEvolutionList, DBN net, File baseDir, String namePrefix, double surpriseMax)
			throws Exception {
			for (int j = 0; j < nodeEvolutionList.get(0).length; j++) {
			List<DynamicNodeProperty> list = new ArrayList<>();
			for (int i = 0; i < nodeEvolutionList.size(); i++) {
				list.add(nodeEvolutionList.get(i)[j]);
			}
			createEvolutionChartForNode(list, net, surpriseMax, new File(baseDir, namePrefix+"_"+list.get(0).getNode()+".pdf"));
		}

	}

	public static void createEvolutionChartForNode(
			List<DynamicNodeProperty> nodeEvolutionList, DBN net, double surpriseMax, File output)
			throws Exception {
		// step 1
		Document document = new Document();
		// step 2
		PdfWriter writer = PdfWriter.getInstance(document,
				new FileOutputStream(output));
		// step 3
		document.open();
		// step 4
		PdfContentByte cb = writer.getDirectContent();

		List<DynamicNodeProperty> list = new ArrayList<>();
		for (int i = 0; i < nodeEvolutionList.size(); i++) {
			list.add(nodeEvolutionList.get(i));
		}
		createChartsForOneNode(list, net, cb, surpriseMax, -1.0);

		// step 5
		document.close();
	}

}
